package DataStructure.QueueLearning.QueueArray;

/**
 *  手动实现一个集合类
 *  数据结构: 队列
 *  底层: 循环数组
 */
public class MyQueueArray <T> {

    private final int INIT_CAPACITY = 10; //默认的初始容量
    private final int MAX_CAPACITY = Integer.MAX_VALUE - 8 ;//最大阈值
    private Object [] arrs;//底层数组
    private int size;// 元素存储数量
    private int head; // 头指向(下标)
    private int end;// 尾指向(下标)

    public MyQueueArray(){
        arrs = new Object[INIT_CAPACITY];
    }
    public MyQueueArray(int initCapacity){
        if (initCapacity <= 0 || initCapacity > MAX_CAPACITY)throw new IllegalArgumentException("initCapacity = "+ initCapacity);

        arrs = new Object[initCapacity];
    }

    public boolean offer(T t){
        if (t == null) throw  new IllegalArgumentException("parame is null");

        if (size == 0){// 队列为空
            arrs[head] = t;
            end = head;
            size++;
            return true;
        }

        if (size == arrs.length){// 数组存满了
            int newLen = getLen();
            grow(newLen);
        }

        // 可以存储

        // 尾指向后移(有可能从数组末尾移动到数组下标0的位置)
        end = (end + 1) % arrs.length;
        arrs[end] = t;// 把元素添加到新的(移动过之后的)的尾位置
        size++;
        return true;
    }

    private void grow(int newLen) {
        // 创建一个新数组
        Object[] objects = new Object[newLen];
        // 把旧数组的数据转移到新数组
        for (int i = 0; i < size; i++) {
            int index = (head + i) % arrs.length;

            objects[i] = arrs[index];
        }

        arrs = objects;
        head = 0;
        end = size - 1;
    }


    private int getLen() {
        // 获取一个新的扩容长度
        int oldLen = arrs.length;
        int newLen = oldLen << 1;// 新长度是旧长度的两倍
        // int newLen = oldLen + (oldLen >> 1);

        if (newLen < 0  || newLen > MAX_CAPACITY){
            // 新扩容的参数太大了.
            newLen = MAX_CAPACITY;
        }

        if (oldLen == newLen){
            // 组数只能这么大了
            throw  new RuntimeException("arr is max");
        }

        return newLen;
    }

    public T poll(){
        if (isEmpty())return null;

        // 不空;
        // head 后移
        T oldValue = (T)arrs[head];// 记录旧值

        head = (head + 1) % arrs.length;
        size--;
        return oldValue;
    }

    public boolean isEmpty() {
        return size == 0;
    }


    public T peek(){
        if (isEmpty()) return null;
        return (T)arrs[head];
    }

    public int size(){
        return size;
    }


    @Override
    public String toString() {


        for (int i = 0; i < size; i++) {
            // 注意这个遍历公式
            int index = (head + i) % arrs.length;
            System.out.print(arrs[index] + "   ");
        }

        return "";
    }
}
